﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Linq;

namespace OkTool.Util
{
    public class DelegateUtil
    {



        public static readonly DelegateUtil Instance = new DelegateUtil();
        private readonly Dictionary<Type, Delegate> _delegates = new Dictionary<Type, Delegate>();

        private DelegateUtil()
        {
        }

        /// <summary>
        /// 添加委托(无返回值)
        /// <para>DelegateUtil.Instance.Add&lt;LogEntity>(TestMethod2);</para>
        /// <para> public void TestMethod2( dog d)</para>
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="listener"></param>
        public void Add<T>(Action<T> listener) where T : EventArgs
        {
            if (this._delegates.TryGetValue(typeof(T), out var a))
            {
                this._delegates[typeof(T)] = Delegate.Combine(a, listener);
            }
            else
            {
                this._delegates[typeof(T)] = listener;
            }
        }

        /// <summary>
        /// 添加委托(有回值)
        ///<para>DelegateUtil.Instance.Add&lt;LogEntity,int>(TestMethod3);</para>
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <typeparam name="Tout"></typeparam>
        /// <param name="listener"></param>
        public void Add<T, Tout>(Func<T, Tout> listener) where T : EventArgs
        {
            if (this._delegates.TryGetValue(typeof(T), out var a))
            {
                this._delegates[typeof(T)] = Delegate.Combine(a, listener);
            }
            else
            {
                this._delegates[typeof(T)] = listener;
            }
        }

        /// <summary>
        /// 回调(无返回值)
        /// <para> DelegateUtil.Instance.Invoke(new LogEntity { });</para>
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="e"></param>
        /// <exception cref="ArgumentNullException"></exception>
        public void Invoke<T>(T e) where T : EventArgs
        {
            if (e == null)
            {
                throw new ArgumentNullException("e");
            }
            if (this._delegates.TryGetValue(typeof(T), out var d))
            {
                var eventDelegate = d as Action<T>;
                eventDelegate.Invoke(e);
            }

        }

        /// <summary>
        /// 回调(有返回值)
        /// <para>var dd=DelegateUtil.Instance.Invoked&lt;LogEntity,int>(new LogEntity { });</para>
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <typeparam name="Tout"></typeparam>
        /// <param name="e"></param>
        /// <returns></returns>
        /// <exception cref="ArgumentNullException"></exception>
        public Tout Invoke<T, Tout>(T e) where T : EventArgs
        {
            if (e == null)
            {
                throw new ArgumentNullException("e");
            }
            if (this._delegates.TryGetValue(typeof(T), out var d))
            {
                var eventDelegate = d as Func<T, Tout>;
                return eventDelegate.Invoke(e);
            }
            return default;
        }


        /// <summary>
        /// 删除委托
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="listener"></param>
        public void Remove<T>(Action<T> listener) where T : EventArgs
        {
            if (this._delegates.TryGetValue(typeof(T), out var source))
            {
                Delegate @delegate = Delegate.Remove(source, listener);
                if (@delegate == null)
                {
                    this._delegates.Remove(typeof(T));
                }
                else
                {
                    this._delegates[typeof(T)] = @delegate;
                }
            }
        }

        /// <summary>
        /// 删除委托
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <typeparam name="Tout"></typeparam>
        /// <param name="listener"></param>
        public void Remove<T, Tout>(Func<T, Tout> listener) where T : EventArgs
        {
            if (this._delegates.TryGetValue(typeof(T), out var source))
            {
                Delegate @delegate = Delegate.Remove(source, listener);
                if (@delegate == null)
                {
                    this._delegates.Remove(typeof(T));
                }
                else
                {
                    this._delegates[typeof(T)] = @delegate;
                }
            }
        }
      
    }
}



